package post

import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	esmodel "mall/common/esmodel/blog"
	"mall/common/globalkey"
	"mall/service/backend/common/errorx"
	"mall/service/backend/common/i18n"
	"mall/service/forum/model"
	"mall/service/forum/rpc/internal/svc"
	"mall/service/forum/rpc/types/forum"

	"github.com/elastic/go-elasticsearch/v7/esapi"
	"github.com/sirupsen/logrus"
	"github.com/zeromicro/go-zero/core/logx"
)

type DiagnosePostToEsLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewDiagnosePostToEsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DiagnosePostToEsLogic {
	return &DiagnosePostToEsLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *DiagnosePostToEsLogic) DiagnosePostToEs(in *forum.BackendPostListReq) (*forum.BackendPostListResp, error) {
	total, err := l.addEntriesToEs(in)
	if err != nil {
		logx.Infow("DiagnosePostToEs err", logx.Field("detail", err.Error()))
		return nil, err
	}

	return &forum.BackendPostListResp{
		Total: total,
	}, nil
}

func (l *DiagnosePostToEsLogic) addEntriesToEs(in *forum.BackendPostListReq) (uint64, error) {
	filterMap := make(map[string]map[string][]any)
	filterMap[model.ForumPostColumns.PostStatus] = map[string][]any{
		"equalTo": {globalkey.PostStatusPublish},
	}
	filterMap[model.ForumPostColumns.ForumID] = map[string][]any{
		"in": {l.svcCtx.Config.Query.PostForumId, l.svcCtx.Config.Query.ColumnForumId},
	}
	entryList, _, err := l.svcCtx.Post.GetList(l.ctx, model.M{
		"page":     in.Page,
		"pageSize": in.PageSize,
		"orderBy":  model.ForumPostColumns.PostID,
	}, -1, filterMap)
	if err != nil {
		return 0, err
	}

	if len(entryList) == 0 {
		return 0, nil
	}

	var res []*esmodel.Post
	for _, v := range entryList {
		res = append(res, &esmodel.Post{
			Id:      v.PostID,
			Title:   v.PostTitle,
			Excerpt: v.PostExcerpt,
		})
	}

	//添加es
	if len(res) > 0 {
		for _, v := range res {
			err := l.addEsData(context.Background(), v)
			if err != nil {
				return 0, err
			}
		}
	}

	return uint64(len(res)), nil
}

func (l *DiagnosePostToEsLogic) addEsData(ctx context.Context, post *esmodel.Post) error {
	// Build the request body.
	// Marshal Elasticsearch document struct object to JSON string
	docStr, err := l.jsonStruct(post)
	if err != nil {
		return err
	}

	id := strconv.FormatUint(post.Id, 10)
	req := esapi.IndexRequest{
		Index:      "scentrobe-forum-post",
		DocumentID: id,
		Body:       strings.NewReader(docStr),
		Refresh:    "false",
	}
	// Return an API response object from request
	res, err := req.Do(ctx, l.svcCtx.EsClient)
	if err != nil {
		logrus.Info(fmt.Sprintf("IndexRequest getting response ERROR: %+v", err))
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		logrus.Info(fmt.Sprintf("[%s] ERROR indexing document ID=%s, %+v", res.Status(), post.Id, res))
		return errorx.NewInvalidArgumentError(i18n.ValidationError)
	}

	// Deserialize the response into a map.
	var resMap map[string]any
	if err = json.NewDecoder(res.Body).Decode(&resMap); err != nil {
		logrus.Info(fmt.Sprintf("Error parsing the response body: %s", err))
		return err
	}

	// logrus.Info(fmt.Sprintf("\nIndexRequest() RESPONSE:"))
	// // Print the response status and indexed document version.
	// logrus.Info(fmt.Sprintf("Status: %v", res.Status()))
	// logrus.Info(fmt.Sprintf("Result: %v", resMap["result"]))
	// logrus.Info(fmt.Sprintf("Version: %d", int(resMap["_version"].(float64))))
	// logrus.Info(fmt.Sprintf("resMap: %+v", resMap))
	// map[_id:40035 _index:scentrobe-kb-entry _primary_term:1 _seq_no:0 _shards:map[failed:0 successful:1 total:2] _type:_doc _version:1 result:created]
	// logrus.Info(fmt.Sprintf("\n"))

	return nil
}

// A function for marshaling structs to JSON string
func (l *DiagnosePostToEsLogic) jsonStruct(post *esmodel.Post) (string, error) {
	// logrus.Info(fmt.Sprintf("jsonStruct docStruct: %+v", entry))

	// Marshal the struct to JSON and check for errors
	b, err := json.Marshal(post)
	if err != nil {
		logrus.Info(fmt.Sprintf("AddEsData jsonStruct json.Marshal ERROR: %+v", err))
		return "", err
	}

	return string(b), nil
}
